package com.learn.netty.reactor;

import com.learn.netty.bio.multithread.PrintUtils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;

final class Handler implements Runnable {

    final SocketChannel socketChannel;
    final SelectionKey selectionKey;
    ByteBuffer input = ByteBuffer.allocate(1024);
    ByteBuffer output = ByteBuffer.allocate(1024);
    static final int READING = 0, SENDING = 1;
    int state = READING;

    public Handler(Selector selector, SocketChannel socketChannel) throws IOException {
        this.socketChannel = socketChannel;
        this.socketChannel.configureBlocking(false);
        // 可选尝试先读
        this.selectionKey = socketChannel.register(selector, 0);
        this.selectionKey.attach(this);
        this.selectionKey.interestOps(SelectionKey.OP_READ);
        PrintUtils.printLog("selector register socketChannel->OP_READ");
        selector.wakeup();
    }

    @Override
    public void run() {
        try {
            if (state == READING) {
                read();
            } else if (state == SENDING) {
                send();
            }
        } catch (IOException e) {
            e.printStackTrace();
            selectionKey.cancel();
        }
    }

    private void send() throws IOException {
        socketChannel.write(output);
        if (outputIsComplete()) {
            selectionKey.cancel();
        }
    }

    private boolean outputIsComplete() throws IOException {
        output.flip();
        output.put("OK".getBytes());
        socketChannel.write(output);
        return true;
    }

    private void read() throws IOException {
        socketChannel.read(input);
        if (inputIsComplete()) {
            process();
            state = SENDING;
            selectionKey.interestOps(SelectionKey.OP_WRITE);
        }
    }

    private void process() {
        PrintUtils.printLog("do process");
    }

    private boolean inputIsComplete() throws IOException {
        input.flip();
        byte[] bytes = new byte[input.remaining()];
        input.get(bytes);
        PrintUtils.printLog(String.format("recv: %s from %s", new String(bytes, StandardCharsets.UTF_8), socketChannel.getRemoteAddress()));
        return true;
    }
}
